﻿#if STEAM_NETWORK
using Steamworks;
using System;

namespace Manox.Libs.Networking.Steam
{
    /// <summary>
    /// Steam network client.
    /// </summary>
    public class SteamNetworkClient : SteamNetworkNode, INetworkClient
    {
        /// <summary>Response action.</summary>        
        private Action<INetworkMatch> ResponseAction;
        /// <summary>Response action.</summary>        
        private NetworkResponseDelegate<bool> JoinedAction;
        /// <summary>Lobby match list.</summary>
        private CallResult<LobbyMatchList_t> LobbyMatchList;
        /// <summary>Lobby match list.</summary>
        private CallResult<LobbyEnter_t> MatchConnected;
        /// <summary>Lobby match list.</summary>
        private CallResult<LobbyDataUpdate_t> MatchDataUpdate;
        /// <summary>Connection id.</summary>
        private SteamNetworkConnectionId ConnectionId;


        /// <summary>
        /// Get matches.
        /// </summary>
        /// <param name="responseAction"></param>
        public void GetMatches(Action<INetworkMatch> responseAction)
        {
            this.ResponseAction = responseAction;

            this.LobbyMatchList = CallResult<LobbyMatchList_t>.Create(this.OnLobbyMatchList);                       

            this.LobbyMatchList.Set(SteamMatchmaking.RequestLobbyList());

            this.MatchDataUpdate = CallResult<LobbyDataUpdate_t>.Create();
    }

        /// <summary>
        /// On lobby match list.
        /// </summary>
        /// <param name="list"></param>
        /// <param name="failed"></param>
        public void OnLobbyMatchList(LobbyMatchList_t list, bool failed)
        {
            if (this.ResponseAction == null || failed)
                return;

            // lobbies are returned in order of closeness to the user, so add them to the list in that order
            for (int iLobby = 0; iLobby < list.m_nLobbiesMatching; iLobby++)
            {
                CSteamID steamIDLobby = SteamMatchmaking.GetLobbyByIndex(iLobby);

                SteamNetworkMatch newMatch = new SteamNetworkMatch();
                newMatch.LobbyId = steamIDLobby;
                newMatch.Name = SteamMatchmaking.GetLobbyData(steamIDLobby, "name");

                if (string.IsNullOrEmpty(newMatch.Name))
                    SteamMatchmaking.RequestLobbyData(steamIDLobby);
                else
                    this.ResponseAction(newMatch);

                //if (pchLobbyName && pchLobbyName[0])
                //{
                //    // set the lobby name
                //    sprintf_safe(lobby.m_rgchName, "%s", pchLobbyName);
                //}
                //else
                //{
                //    // we don't have info about the lobby yet, request it
                //    SteamMatchmaking()->RequestLobbyData(steamIDLobby);
                //    // results will be returned via LobbyDataUpdate_t callback
                //    sprintf_safe(lobby.m_rgchName, "Lobby %d", steamIDLobby.GetAccountID());
                //}
            }
        }

        /// <summary>
        /// On match 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="failed"></param>
        private void OnMatchDataUpdate(LobbyDataUpdate_t data, bool failed)
        {

        }

        /// <summary>
        /// Connect.
        /// </summary>
        /// <param name="match"></param>
        /// <param name="password"></param>
        /// <param name="joinedAction"></param>
        public void Connect(INetworkMatch match, string password, NetworkResponseDelegate<bool> joinedAction)
        {
            this.JoinedAction = joinedAction;

            this.MatchConnected = CallResult<LobbyEnter_t>.Create(this.OnMatchConnected);

            this.MatchConnected.Set(SteamMatchmaking.JoinLobby((match as SteamNetworkMatch).LobbyId));            
        }

        /// <summary>
        /// On match connected.
        /// </summary>
        /// <param name="match"></param>
        /// <param name="failed"></param>
        public void OnMatchConnected(LobbyEnter_t match, bool failed)
        {
            if (failed || match.m_EChatRoomEnterResponse == 0)
                return;

            this.ConnectionId = new SteamNetworkConnectionId(SteamMatchmaking.GetLobbyOwner((CSteamID)match.m_ulSteamIDLobby));

            if (this.JoinedAction != null)
                this.JoinedAction(true);
        }

        /// <summary>
        /// Send data.
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="data"></param>
        /// <param name="dataLength"></param>
        public void Send(byte[] data, int dataLength)
        {
            this.Send(this.ConnectionId, data, dataLength);
        }
    }
}
#endif
